Skip to content

Conversation

@quic-areg
Copy link
Contributor

-z separate-code puts the text segment in its
own pages disjoint from any other segments.

Copy link
Contributor

@quic-seaswara quic-seaswara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we import the tests from lld for this as part of this PR ?

`-z separate-code` puts the text segment in its
own pages disjoint from any other segments.
Copy link
Contributor

@quic-seaswara quic-seaswara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have other options that are not compatible with -z seperate-code ?

How does using PHDR's, MEMORY, linker scripts, Adding LMA addresses, Using linker special directives (BYTE, QUAD, SQUAD, etc), orphan section placements work with this option ? Can you explore more with using the bfd linker ?

How does -z relro work this option ?

We might need to add a FAQ also for cases that people might want to consider this option for image size constraints, adding a new segment can cause increase in image size for example.

These analysis could be seperate bugs, and it might deserve an epic as applicable.

Does these -z options translate to reproduce command line option appropriately ?

Can we document incompatibilities ? and also document this option in detail.

I would prefer a test that can build and run in addition to a lit unit test.

You can decide to make some of these as follow ups with some discretion.

bool PrevExec = (PrevSegIt->second.front()->flag() & llvm::ELF::PF_X);
return PrevExec != IsExec;
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to something better since the lambda does nore than aligning segments to a page ?

Why does aligning segments to a page not work with -z seperate-code ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to something better since the lambda does nore than aligning segments to a page ?

If it does anything more than determine whether or not segments should be page aligned then I did something wrong. Taking another look, I am not seeing that it does anything other than that. What am I missing? What name do you suggest?

Why does aligning segments to a page not work with -z seperate-code ?

I am not sure if I understand your question. It does "work". Starting code segments at page aligned offsets ensures that they are not co-resident on the same page as other segments. That is the point of this lambda function: when transitioning to/from a code segment to another kind of segment, with -z separate-code the next segment should be page aligned. That is my understanding anyways

Copy link
Contributor

@quic-seaswara quic-seaswara Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda checks for the variety of things

  • align segments to a page
  • checks for the last section added to the segment and sees if it has execute permissions (SeperateSegmentKind for code)

Should this be called DoPageAlignment or NeedSeperateSegmentOrPageAlign ?

Copy link
Contributor Author

@quic-areg quic-areg Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checks for the last section added to the segment and sees if it has execute permissions (SeperateSegmentKind for code)

Because it is relevant to determine if we ShouldPageAlignSegments?

It checks if we should page align segments based on:

  1. --align-segments/no-align-segments
  2. if we have a linker script
  3. -z separate-code. This requires looking at transitions to/from executable segments

Should this be called DoPageAlignment or NeedSeperateSegmentOrPageAlign

I don't see how these are better names. They sound like (worse) synonyms to me.

Copy link
Member

@partaror partaror left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option is affecting all the targets, however, the test is added just for x86. Can we add a test in the common/Standalone subdirectory as well?

NoExecStack,
NoGnuStack,
SeparateCode,
NoseparateCode,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be better?

Suggested change
NoseparateCode,
NoSeparateCode,


auto SeparateKind = config().options().getSeparateSegmentKind();
bool ShouldSeparate =
!linkerScriptHasSectionsCommand &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the -z separate-code option only takes affect when the linker script does not have SECTIONS command. Should we report a warning if this option is used along with the SECTIONS command?

@quic-seaswara
Copy link
Contributor

I took some time to write test cases, it looks like there is some behavioral difference with these switches with linker script, omagic support, and shared library support.

@quic-areg can you please look into this usage, though we dont need to copy exact bfd behavior in cases where the linker gets confused and creates a segment that mixes R/RW/RWX.

Please see this test and let me know how we plan to address this both in diagnostics and other comments we have raised.

cat > 1.c << \!
int bss[10] = { 0 };
const int mydata[] = { 1, 2, 3, 4};
int foo() { return 0; }
int bar() { return 0; }
int baz() { return 0; }
!

cat > script.t << \!
SECTIONS {
  .foo : { *(.text.foo) }
  .rodata : { *(.rodata*) }
  .data : { *(.data*) }
  .bar : { *(.text.bar) }
  .baz : { *(.text.baz) }
  .bss : { *(.bss.*) }
}
!

clang -c -target x86_64 1.c -fPIC
echo "****************************************"
echo "No linker script ....."
echo "****************************************"
ld.bfd 1.o -z separate-code -o nols.1
readelf -l -W nols.1
echo "****************************************"
echo "No linker script ....omagic."
echo "****************************************"
ld.bfd 1.o -z separate-code -o nols.omagic -N
readelf -l -W nols.omagic
echo "****************************************"
echo "No linker script ....partial link."
echo "****************************************"
ld.bfd 1.o -z separate-code -o nols.partiallink -r
readelf -S -W nols.partiallink
echo "****************************************"
echo "No linker script ....shared library"
echo "****************************************"
ld.bfd 1.o -z separate-code -shared -o nols.shared.1
readelf -l -W nols.shared.1
echo "****************************************"
echo "No linker script ....."
echo "****************************************"
ld.bfd 1.o -z no-separate-code -o nols.no.1
readelf -l -W nols.no.1
echo "****************************************"
echo "No linker script ....omagic."
echo "****************************************"
ld.bfd 1.o -z no-separate-code -o nols.no.omagic -N
readelf -l -W nols.no.omagic
echo "****************************************"
echo "No linker script ....shared library"
echo "****************************************"
ld.bfd 1.o -z no-separate-code -shared -o nols.no.shared.1
readelf -l -W nols.no.shared.1
echo "****************************************"
echo "linker script ....."
echo "****************************************"
ld.bfd 1.o -z separate-code -o nols.1  -T script.t
readelf -l -W nols.1
echo "No linker script ....omagic."
ld.bfd 1.o -z separate-code -o nols.omagic -N -T script.t
readelf -l -W nols.omagic
echo "No linker script ....partial link."
ld.bfd 1.o -z separate-code -o nols.partiallink -r -T script.t
readelf -S -W nols.partiallink
echo "No linker script ....shared library"
ld.bfd 1.o -z separate-code -shared -o nols.shared.1 -T script.t
readelf -l -W nols.shared.1
echo "No linker script ....."
ld.bfd 1.o -z no-separate-code -o nols.no.1 -T script.t
readelf -l -W nols.no.1
echo "No linker script ....omagic."
ld.bfd 1.o -z no-separate-code -o nols.no.omagic -N -T script.t
readelf -l -W nols.no.omagic
echo "No linker script ....shared library"
ld.bfd 1.o -z no-separate-code -shared -o nols.no.shared.1 -T script.t
readelf -l -W nols.no.shared.1

@quic-areg
Copy link
Contributor Author

it looks like there is some behavioral difference with these switches with linker script, omagic support, and shared library support

It is expected that readelf -l would differ with the absence/presence of these options.

mixing -z separate-code with partial linking, omagic, or linker scripts does not make sense. We could warn for these combinations though neither lld nor bfd currently do.

@quic-seaswara
Copy link
Contributor

it looks like there is some behavioral difference with these switches with linker script, omagic support, and shared library support

It is expected that readelf -l would differ with the absence/presence of these options.

mixing -z separate-code with partial linking, omagic, or linker scripts does not make sense. We could warn for these combinations though neither lld nor bfd currently do.

Mixing -z seperate-code with omagic makes the linker choose omagic behavior, if you observe.

For shared libraries -z separate-code is not effective, if you see.

Since -z relro also bumps the page alignment for certain sections when they are seen in the program layout, doesn't it conflict ?

I am not sure why it does not make sense with linker scripts, does -z separate-code option always create aligned segments to page boundaries ?

@quic-areg
Copy link
Contributor Author

it looks like there is some behavioral difference with these switches with linker script, omagic support, and shared library support

It is expected that readelf -l would differ with the absence/presence of these options.
mixing -z separate-code with partial linking, omagic, or linker scripts does not make sense. We could warn for these combinations though neither lld nor bfd currently do.

Mixing -z seperate-code with omagic makes the linker choose omagic behavior, if you observe.

For shared libraries -z separate-code is not effective, if you see.

Since -z relro also bumps the page alignment for certain sections when they are seen in the program layout, doesn't it conflict ?

I am not sure why it does not make sense with linker scripts, does -z separate-code option always create aligned segments to page boundaries ?

Mixing -z seperate-code with omagic makes the linker choose omagic behavior, if you observe.

Yes I observed this. It makes no sense to request an RWX segment (omagic) along with a separate code segment. The options should not be mixed. both eld,lld,and bfd behave the same way when they are mixed (omagic takes precedence), if you observe:

ld.eld 1.o --omagic -z separate-code --omagic -o e.out --rosegment --no-align-segments 
ld.lld 1.o --omagic -z separate-code --omagic -o l.out  
ld.bfd 1.o --omagic -z separate-code --omagic -o b.out 
llvm-readelf -l e.out l.out b.out

  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x000138 0x000168 RWE 0x10

  LOAD           0x0000b0 0x00000000002000b0 0x00000000002000b0 0x0000b8 0x0000e8 RWE 0x10

  LOAD           0x0000b0 0x00000000004000b0 0x00000000004000b0 0x0000b8 0x0000e8 RWE 0x10

For shared libraries -z separate-code is not effective, if you see.

I guess I am missing something. Can you show an example?

here's my example, if you see

ld.eld -shared 1.o -z separate-code -o e.out --rosegment --no-align-segments
ld.lld -shared 1.o -z separate-code -o l.out
ld.bfd -shared 1.o -z separate-code -o b.out
llvm-readelf -l e.out l.out b.out

  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000190 0x000190 R E 0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x0000e4 0x0000e4 R   0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000028 0x000028 R E 0x1000
  LOAD           0x003000 0x0000000000003000 0x0000000000003000 0x000088 0x000088 R   0x1000
  LOAD           0x003088 0x0000000000003088 0x0000000000003088 0x0000e0 0x000110 RW  0x1000

  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x00039c 0x00039c R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x000028 0x000028 R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000070 0x001000 RW  0x1000
  LOAD           0x002070 0x0000000000003070 0x0000000000003070 0x000000 0x000028 RW  0x1000

  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0002d8 0x0002d8 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x000028 0x000028 R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000088 0x000088 R   0x1000
  LOAD           0x002f40 0x0000000000003f40 0x0000000000003f40 0x0000c0 0x0000e8 RW  0x1000

The code segments are all in their own pages; it looks 'effective' to me. The other segments are allowed to overlap.

why are you adding --rosegment and --no-align-segments. can we just do -z separate-code?

eld page-aligns segments by default when there is no linker script present, so the effect of -z separate-code cannot be seen. eld also does not emit a separate ro segment, which the other linkers do. This is important because we need more segments to show that r/rw segments may overlap and that only code segments are aligned. this cannot be seen when there are only two segments, which I believe is the default

Since -z relro also bumps the page alignment for certain sections when they are seen in the program layout, doesn't it conflict ?

No I don't think so. Do you have an example?

I am not sure why it does not make sense with linker scripts, does -z separate-code option always create aligned segments to page boundaries ?

If the user has a linker script then they should own the layout/page alignment decisions. eg we page align segments by default when there is no linker script, but this is not turned on with linker scripts. lld does not honor -z separate-code with linker scripts for example.

does -z separate-code option always create aligned segments to page boundaries ?

starting code segments at page aligned offsets is one way to ensure that they are not co-resident on the same page as any other segment, and that seems to be how the other linkers implement it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants